package com.cm.log_process.log_query.service.impl;

import com.cm.log_process.log_common.config.ConfigBean;
import com.cm.log_process.log_common.entity.Log;
import com.cm.log_process.log_common.entity.PageResult;
import com.cm.log_process.log_common.entity.RequestParam;
import com.cm.log_process.log_common.reg.BusinessRegexp;
import com.cm.log_process.log_query.dao.QueryDao;
import com.cm.log_process.log_query.service.MultiQueryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * Creator:郭兆鹏
 * Date:2019/12/16
 * 思路：复杂查询实现类
 */
@Slf4j
@Service
public class MultiQueryServiceImpl implements MultiQueryService {
    @Autowired
    private QueryDao queryDao;

    //=============================guozhaopeng================================
    @Override
    public PageResult<Log> multiSearch(RequestParam param) {
        PageRequest pageRequest = PageRequest.of(param.getPageIndex()-1,param.getPageSize());
        //创建查询复合条件
        BoolQueryBuilder transQuery = new BoolQueryBuilder().          //创建布尔过滤器
                must(QueryBuilders.termQuery("transId", param.getTransId())).  //精确根据流水单号查询
                filter(QueryBuilders.rangeQuery("timestamp").from(param.getStartTime()).to(param.getEndTime()));
        transQuery.must(QueryBuilders.matchQuery("message",param.getPhoneNum()));
        //判断是否有文件类型查询条件
        if(StringUtils.isNotEmpty(param.getFileType())){
            transQuery.must(QueryBuilders.matchQuery("fileType",param.getFileType()));
        }
        //设置排序条件，降序
        SortBuilder sortBuilder = SortBuilders.fieldSort("timestamp").order(SortOrder.DESC);
        //组装聚合查询条件
        SearchQuery searchQuery = new NativeSearchQueryBuilder().
                withQuery(transQuery).
                withPageable(pageRequest).
                withSort(sortBuilder).
                build();
        //进行查询
        Page<Log> search = queryDao.search(searchQuery);
        List<Log> logs = getLogs(search);
        return new PageResult<>(logs,search.getTotalElements());
    }


    //根据手机号进行查询
    @Override
    public PageResult<Log> byPhoneNum(RequestParam param) {
        //查询分页条件
        PageRequest request = PageRequest.of(param.getPageIndex()-1,param.getPageSize());
        BoolQueryBuilder query = new BoolQueryBuilder()
                .must(QueryBuilders.wildcardQuery("message",("*"+param.getPhoneNum()+"*").toLowerCase()));
        query.filter(QueryBuilders.rangeQuery("timestamp").gte(param.getStartTime()).lte(param.getEndTime()));

        if(StringUtils.isNotEmpty(param.getFileType())){
            query.must(QueryBuilders.matchQuery("fileType",param.getFileType()));
        }
        //降序排序
        SortBuilder sortBuilder = SortBuilders.fieldSort("timestamp").order(SortOrder.DESC);
        //构建查询体
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(query)
                .withPageable(request)
                .withSort(sortBuilder)
                .build();
        //牺牲查询效率，手动刷新再查询，确保数据查询时的实时性
        //queryDao.refresh();
        //查询
        Page<Log> search = queryDao.search(searchQuery);
        //遍历根据正则表达式取出符合条件的日志
        List<Log> logs = getLogs(search);
        return new PageResult<Log>(logs, search.getTotalElements());
    }

    //遍历取出符合条件的日志集合
    private List<Log> getLogs(Page<Log> search) {
        List<Log> logs = new ArrayList<>();
        for (Log el : search.getContent()) {
            BusinessRegexp regexp = new BusinessRegexp();
            if(!(el.getFileType().equalsIgnoreCase("INFO"))){
                if(regexp.testPhoneNum(el.getMessage())){
                    logs.add(el);
                }
            }
        }
        return logs;
    }
    //=============================guozhaopeng================================

    //=============================shenwanlong===============================
    /**
    *@Date 2019/12/31
    *@Author 沈万龙
    *作用:根据流水单号
    */
    @Override
    public PageResult<Log> byTransId(RequestParam param) {
        //动态获取索引名
        ConfigBean.setIndexName(param.getIndexName());
        //创建Builder来创建索引对象
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        //范围查询
        RangeQueryBuilder range = QueryBuilders.rangeQuery("timestamp");
        //判断类型是否为空
        if (StringUtils.isNotEmpty(param.getFileType())){
            //已经动态修改了索引名，所以只需要业务流水号transId
            builder.must(QueryBuilders.matchQuery("transId", param.getTransId()));
            builder.must(QueryBuilders.matchQuery("fileType", param.getFileType()));
        }else {//如果类型为空，则只根据流水号查询
            builder.must(QueryBuilders.matchQuery("transId", param.getTransId()));
        }
        //构建时间的查询条件
        builder.must(range.gte(param.getStartTime())
                .lte(param.getEndTime()));
        //创建分页对象(Es的分页api是从第0页开始的)
        Pageable pageable = PageRequest.of(param.getPageIndex() - 1, param.getPageSize());
        //设置字段的排序(按照时间戳降序排序)
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("timestamp").order(SortOrder.DESC);
        //构建查询
        SearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(builder)//将查询条件设置构建中
                .withPageable(pageable)//将分页条件设置到构建中
                .withSort(sortBuilder)//将排序设置到构建中
                .build();
        Page<Log> logPage = queryDao.search(query);
        //获取记录的总条数
        long total = logPage.getTotalElements();
        //获取记录的内容
        List<Log> content = logPage.getContent();
        return new PageResult<>(content, total);
    }
    //=============================shenwanlong===============================


    //=============================huangpengxing==============================
    /**
     *@Date 2019/12/12
     *@Author 黄鹏星
     *功能: 通过主机和时间戳查询日志
     */
    @Override
    public PageResult<Log> byHostIp(RequestParam param) {
        //创建分页对象
        Pageable pageable = PageRequest.of((param.getPageIndex()) - 1, param.getPageSize());
        //创建检索字段
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.matchQuery("hostIp", param.getHostIp()));   //精确查询ip字段
        //判断类型字段是否为空
        if (StringUtils.isNotEmpty(param.getFileType())) {
            boolQuery.filter(QueryBuilders.matchQuery("fileType", param.getFileType()));
        }
        //创建时间范围查询字段
        boolQuery.filter(QueryBuilders.rangeQuery("timestamp")
                .gte(param.getStartTime())
                .lte(param.getEndTime()));
        //创建时间排序询字段
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("timestamp")
                .order(SortOrder.DESC);//降序查询
        //创建查询构建器
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withPageable(pageable)
                .withSort(sortBuilder)
                .build();
        Page<Log> logPage = queryDao.search(searchQuery);
        //返还(总记录数,内容)
        return new PageResult<>(logPage.getContent(), logPage.getTotalElements());
    }
    //=============================huangpengxing===============================


    //=============================dengzhiyong=================================
    @Override
    public PageResult<Log> findMessageByTimeStamp(RequestParam map) {
        Pageable pageable = PageRequest.of(map.getPageIndex() - 1, map.getPageSize());
        //创建排序字段
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("timestamp")
                .order(SortOrder.DESC);   //查询方式降序
        QueryBuilder rangeQueryBuilder =  QueryBuilders.rangeQuery("timestamp")
                .from(map.getStartTime())
                .to(map.getEndTime());

        QueryBuilder queryBuilder = null;
        if (StringUtils.isNotEmpty(map.getFileType())) {
            queryBuilder = QueryBuilders.matchQuery("fileType", map.getFileType());
        }
        //创建查询构建器
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(rangeQueryBuilder)  //精确查询字段
                .withFilter(queryBuilder)
                .withPageable(pageable)
                .withSort(sortBuilder)
                .build();
        Page<Log> logPage = queryDao.search(searchQuery);
        if (logPage != null && !logPage.isEmpty() && !logPage.getContent().isEmpty()) {
            //获取内容
            List<Log> logList = logPage.getContent();
            //获取字段
            return new PageResult<>(logList, logPage.getTotalElements());
        }
        return new PageResult<>();
    }
    //=============================dengzhiyong=================================
}
